package handlers

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

// App Container Image Discovery Protocol implementation
// Based on the App Container Image Discovery specification

// DiscoveryMeta represents the discovery metadata
type DiscoveryMeta struct {
	ACDiscovery struct {
		Endpoints []DiscoveryEndpoint `json:"endpoints"`
	} `json:"ac-discovery"`
}

// DiscoveryEndpoint represents a discovery endpoint
type DiscoveryEndpoint struct {
	Protocol string            `json:"protocol"`
	URI      string            `json:"uri"`
	Keys     []string          `json:"keys,omitempty"`
	Headers  map[string]string `json:"headers,omitempty"`
}

// AppImageMeta represents app image metadata
type AppImageMeta struct {
	ACKind    string            `json:"acKind"`
	ACVersion string            `json:"acVersion"`
	Name      string            `json:"name"`
	Labels    map[string]string `json:"labels,omitempty"`
	App       AppSpec           `json:"app"`
}

// AppSpec represents the app specification
type AppSpec struct {
	Exec             []string          `json:"exec"`
	User             string            `json:"user,omitempty"`
	Group            string            `json:"group,omitempty"`
	WorkingDirectory string            `json:"workingDirectory,omitempty"`
	Environment      []EnvVar          `json:"environment,omitempty"`
	MountPoints      []MountPoint      `json:"mountPoints,omitempty"`
	Ports            []Port            `json:"ports,omitempty"`
	Isolators        []Isolator        `json:"isolators,omitempty"`
	Annotations      map[string]string `json:"annotations,omitempty"`
}

// EnvVar represents an environment variable
type EnvVar struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

// MountPoint represents a mount point
type MountPoint struct {
	Name     string `json:"name"`
	Path     string `json:"path"`
	ReadOnly bool   `json:"readOnly,omitempty"`
}

// Port represents a port specification
type Port struct {
	Name     string `json:"name"`
	Protocol string `json:"protocol"`
	Port     uint   `json:"port"`
	Count    uint   `json:"count,omitempty"`
	SocketActivated bool `json:"socketActivated,omitempty"`
}

// Isolator represents resource isolators
type Isolator struct {
	Name  string      `json:"name"`
	Value interface{} `json:"value"`
}

// DiscoveryHandler handles App Container Image Discovery requests
func (h *Handlers) DiscoveryHandler(c *gin.Context) {
	host := c.Request.Host
	scheme := "https"
	if c.Request.TLS == nil {
		scheme = "http"
	}

	// Create discovery metadata
	discovery := DiscoveryMeta{
		ACDiscovery: struct {
			Endpoints []DiscoveryEndpoint `json:"endpoints"`
		}{
			Endpoints: []DiscoveryEndpoint{
				{
					Protocol: "https+docker",
					URI:      fmt.Sprintf("%s://%s/v2", scheme, host),
					Keys:     []string{"gpg"},
				},
				{
					Protocol: "http+docker",
					URI:      fmt.Sprintf("%s://%s/v2", scheme, host),
				},
			},
		},
	}

	c.Header("Content-Type", "application/json")
	c.JSON(http.StatusOK, discovery)
}

// GetAppImageMeta handles requests for app image metadata
func (h *Handlers) GetAppImageMeta(c *gin.Context) {
	name := c.Param("name")
	// Remove leading slash from wildcard parameter
	if strings.HasPrefix(name, "/") {
		name = name[1:]
	}
	version := c.Query("version")
	if version == "" {
		version = "latest"
	}

	// Parse the app name to extract components
	parts := strings.Split(name, "/")
	if len(parts) < 2 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid app name format"})
		return
	}

	// Create app image metadata
	appMeta := AppImageMeta{
		ACKind:    "ImageManifest",
		ACVersion: "0.8.11",
		Name:      name,
		Labels: map[string]string{
			"version": version,
			"arch":    "amd64",
			"os":      "linux",
		},
		App: AppSpec{
			Exec: []string{"/bin/sh"},
			User: "0",
			Group: "0",
			WorkingDirectory: "/",
			Environment: []EnvVar{
				{Name: "PATH", Value: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
			},
			Annotations: map[string]string{
				"created": "2025-01-01T00:00:00Z",
				"authors": "CAR Registry",
			},
		},
	}

	c.Header("Content-Type", "application/json")
	c.JSON(http.StatusOK, appMeta)
}

// DiscoverySignature handles signature discovery requests
func (h *Handlers) DiscoverySignature(c *gin.Context) {
	version := c.Query("version")
	if version == "" {
		version = "latest"
	}

	// For now, return a placeholder signature
	// In a real implementation, this would return the actual GPG signature
	signature := map[string]interface{}{
		"signatures": []map[string]string{
			{
				"keyid":     "example-key-id",
				"signature": "example-signature-data",
			},
		},
	}

	c.Header("Content-Type", "application/json")
	c.JSON(http.StatusOK, signature)
}

// ListAppImages handles listing available app images
func (h *Handlers) ListAppImages(c *gin.Context) {
	// Query parameters for filtering
	namespace := c.Query("namespace")
	arch := c.Query("arch")
	os := c.Query("os")

	// Mock data for demonstration
	// In a real implementation, this would query the database
	images := []map[string]interface{}{
		{
			"name":      "example.com/myapp",
			"versions": []string{"1.0.0", "1.1.0", "latest"},
			"arch":     "amd64",
			"os":       "linux",
			"size":     "50MB",
			"created":  "2025-01-01T00:00:00Z",
		},
		{
			"name":      "example.com/webapp",
			"versions": []string{"2.0.0", "2.1.0", "latest"},
			"arch":     "amd64",
			"os":       "linux",
			"size":     "120MB",
			"created":  "2025-01-02T00:00:00Z",
		},
	}

	// Apply filters if provided
	filteredImages := make([]map[string]interface{}, 0)
	for _, img := range images {
		if namespace != "" && !strings.Contains(img["name"].(string), namespace) {
			continue
		}
		if arch != "" && img["arch"] != arch {
			continue
		}
		if os != "" && img["os"] != os {
			continue
		}
		filteredImages = append(filteredImages, img)
	}

	response := map[string]interface{}{
		"images": filteredImages,
		"total":  len(filteredImages),
	}

	c.Header("Content-Type", "application/json")
	c.JSON(http.StatusOK, response)
}

// GetAppImageDetails handles detailed app image information requests
func (h *Handlers) GetAppImageDetails(c *gin.Context) {
	name := c.Param("name")
	// Remove leading slash from wildcard parameter
	if strings.HasPrefix(name, "/") {
		name = name[1:]
	}
	version := c.Query("version")
	if version == "" {
		version = "latest"
	}

	// Mock detailed information
	// In a real implementation, this would query the database and storage
	details := map[string]interface{}{
		"name":        name,
		"version":     version,
		"description": "Sample application container image",
		"arch":        "amd64",
		"os":          "linux",
		"size":        "50MB",
		"layers": []map[string]string{
			{
				"digest": "sha256:example1",
				"size":   "20MB",
			},
			{
				"digest": "sha256:example2",
				"size":   "30MB",
			},
		},
		"created":     "2025-01-01T00:00:00Z",
		"author":      "CAR Registry",
		"annotations": map[string]string{
			"org.opencontainers.image.title":       name,
			"org.opencontainers.image.version":     version,
			"org.opencontainers.image.description": "Sample application",
		},
	}

	c.Header("Content-Type", "application/json")
	c.JSON(http.StatusOK, details)
}